import java.text.DecimalFormat;

/**
 * This class contains a lot of public variables that can be updated
 * by other classes during a simulation, to collect information about
 * the run.
 */
public class Statistics
{
	/** The number of processes that have exited the system */
	public long nofCompletedProcesses = 0;
	/** The number of processes that have entered the system */
	public long nofCreatedProcesses = 0;
	/** The total time that all completed processes have spent waiting for memory */
	public long totalTimeSpentWaitingForMemory = 0;
	/** The time-weighted length of the memory queue, divide this number by the total time to get average queue length */
	public long memoryQueueLengthTime = 0;
	/** The largest memory queue length that has occurred */
	public long memoryQueueLargestLength = 0;
	/** The time-weighted length of the CPU queue, divide this number by the total time to get average queue length */
	public long cpuQueueLengthTime = 0;
	/** The largest CPU queue length that has occurred */
	public long cpuQueueLargestLength = 0;
	/** The time-weighted length of the IO queue, divide this number by the total time to get average queue length */
	public long ioQueueLengthTime = 0;
	/** The largest IO queue length that has occurred */
	public long ioQueueLargestLength = 0;

	
	public long nofForcedProcessSwitches = 0;
	
	public long nofCompletedIOProcesses = 0;
	
	public int totalCpuTimeSpentProcessing = 0;
	
	public int totalCpuTimeSpentProcessingFinished = 0; //Finished processes only
	
	public int totalIOTimeSpentProcessingFinished = 0; //Finished processes only
	
	public int totalCpuTimeSpentWaiting = 0;
	
	public int nofTimesInCpuQueue = 0;
	
	public int nofTimesInIOQueue = 0;
	
	public long averageTimeInSystem = 0;
	
	public long averageTimeWaitingInCpuQueue = 0; 
	
	public long averageTimeWaitingInIOQueue = 0;
	
	private DecimalFormat df = new DecimalFormat("0.00#");
    
	/**
	 * Prints out a report summarizing all collected data about the simulation.
	 * @param simulationLength	The number of milliseconds that the simulation covered.
	 */
	public void printReport(long simulationLength) {
		System.out.println();
		System.out.println("Simulation statistics:");
		System.out.println();
		System.out.println("Number of completed processes:                                "+nofCompletedProcesses);
		System.out.println("Number of created processes:                                  "+nofCreatedProcesses);
		System.out.println("Number of (forced) process switches:                          "+nofForcedProcessSwitches);
		System.out.println("Number of processed I/O operations:                           "+nofCompletedIOProcesses);
		System.out.println("Average throughput (processes per second):                    "+ (df.format((double)nofCompletedProcesses/((double)simulationLength / 1000))));
		System.out.println();
		System.out.println("Total CPU time spent processing:                              "+(totalCpuTimeSpentProcessing) + " ms");
		System.out.println("Fraction of CPU time spent processing:                        "+df.format((double)((totalCpuTimeSpentProcessing * 100))
																						   /(double)(simulationLength)) + "%") ;
		System.out.println("Total CPU time spent waiting:                                 "+(simulationLength - totalCpuTimeSpentProcessing) + " ms");
		System.out.println("Fraction of CPU time spent waiting:                           "+df.format((double)((simulationLength - totalCpuTimeSpentProcessing) * 100)
				   																		   /(double)(simulationLength)) + "%");
		System.out.println();
		System.out.println("Largest occuring memory queue length:                         "+memoryQueueLargestLength);
		System.out.println("Average memory queue length:                                  "+(float)memoryQueueLengthTime/simulationLength);
		System.out.println("Largest occuring cpu queue length:                            "+cpuQueueLargestLength);
		System.out.println("Average cpu queue length:                                     "+(float)cpuQueueLengthTime/simulationLength);
		System.out.println("Largest occuring I/O queue length:                            "+ioQueueLargestLength);
		System.out.println("Average I/O queue length:                                     "+(float)ioQueueLengthTime/simulationLength);
		if(nofCompletedProcesses > 0) {
			System.out.println("Average # of times a process has been placed in memory queue: "+1);
			System.out.println("Average # of times a process has been placed in cpu queue:    "+ (nofTimesInCpuQueue / nofCompletedProcesses));
			System.out.println("Average # of times a process has been placed in I/O queue:    "+ (nofTimesInIOQueue / nofCompletedProcesses));
			System.out.println();
			System.out.println("Average time spent in system per process:                     "+ (averageTimeInSystem / nofCompletedProcesses) + " ms");
			System.out.println("Average time spent waiting for memory per process:            "+ totalTimeSpentWaitingForMemory/nofCompletedProcesses+" ms");
			System.out.println("Average time spent waiting for cpu per process:               "+ (averageTimeWaitingInCpuQueue / nofCompletedProcesses) + " ms");
			System.out.println("Average time spent processing per process:                    "+ (totalCpuTimeSpentProcessingFinished / nofCompletedProcesses) + " ms");
			System.out.println("Average time spent waiting for I/O per process:               "+ (averageTimeWaitingInIOQueue / nofCompletedProcesses) + " ms");
			System.out.println("Average time spent in IO per process:                         "+ (totalIOTimeSpentProcessingFinished / nofCompletedProcesses) + " ms");
		}
	}
}
